/*******************************************************************************
 * 创建: 2025年11月09日
 * 作者: 水煮肉片饭(27185709@qq.com)
 * 描述: 滤镜Shader
 * 支持灰阶, 反转, 素描, 故障, 马赛克, 老照片, 羊皮纸, 电影胶片, 赛博朋克
*******************************************************************************/
import { _decorator, Component, Enum, js, Material, NodeEventType, Sprite, UIRenderer, UITransform, Vec2 } from 'cc';
enum Style { 无, 灰阶, 反转, 素描, 故障, 马赛克, 老照片, 羊皮纸, 电影胶片, 赛博朋克 }
const { ccclass, property, disallowMultiple, executeInEditMode, requireComponent, menu } = _decorator;
@ccclass
@disallowMultiple
@executeInEditMode
@requireComponent(UIRenderer)
@menu('Gi/Shader/FilterFusion')
class FilterFusion extends Component {
    @property({ displayName: '材质', readonly: true })
    materialName: string = '';
    @property
    _style: Style = Style.无;
    @property({ displayName: '滤镜样式', type: Enum(Style) })
    get style() { return this._style; }
    set style(val) { this._style = val; this.material && this.updateStyle(); }
    @property
    _glitchDynamic: boolean = false;
    @property({ displayName: '······故障动态', visible() { return this._style === Style.故障 } })
    get glitchDynamic() { return this._glitchDynamic; }
    set glitchDynamic(val) { this._glitchDynamic = val; this.material?.setProperty('glitchDynamic', val ? 1 : 0); }
    @property
    _glitchAmplitude: number = 0.2;
    @property({ displayName: '······故障幅度', range: [0, 1, 0.01], slide: true, visible() { return this._style === Style.故障 } })
    get glitchAmplitude() { return this._glitchAmplitude; }
    set glitchAmplitude(val) { this._glitchAmplitude = val; this.material?.setProperty('glitchAmplitude', val); }
    @property
    _mosaicSize: Vec2 = new Vec2(8, 8);
    @property({ displayName: '······马赛克尺寸', type: Vec2, visible() { return this._style === Style.马赛克 } })
    get mosaicSize() { return this._mosaicSize; }
    set mosaicSize(val) {
        this._mosaicSize = val = new Vec2(Math.max(val.x, 1) | 0, Math.max(val.y, 1) | 0);
        this.material?.setProperty('mosaicSize', val);
    }
    @property
    _filmDynamic: boolean = false;
    @property({ displayName: '······胶片动态', visible() { return this._style === Style.电影胶片 } })
    get filmDynamic() { return this._filmDynamic; }
    set filmDynamic(val) { this._filmDynamic = val; this.material?.setProperty('filmDynamic', val ? 1 : 0); }
    @property
    _filmGrain: number = 0.1;
    @property({ displayName: '······胶片颗粒', range: [0, 1, 0.01], slide: true, visible() { return this._style === Style.电影胶片 } })
    get filmGrain() { return this._filmGrain; }
    set filmGrain(val) { this._filmGrain = val; this.material?.setProperty('filmGrain', val); }

    @property
    _filmScratch: number = 0.5;
    @property({ displayName: '······胶片划痕', range: [0, 1, 0.01], slide: true, visible() { return this._style === Style.电影胶片 } })
    get filmScratch() { return this._filmScratch; }
    set filmScratch(val) { this._filmScratch = val; this.material?.setProperty('filmScratch', val); }
    @property
    _hue: number = 0;
    @property({ displayName: '色相', range: [-1, 1, 0.01], slide: true })
    get hue() { return this._hue; }
    set hue(val) { this._hue = val; this.material?.setProperty('hue', val); }
    @property
    _saturation: number = 0;
    @property({ displayName: '饱和度', range: [-1, 1, 0.01], slide: true })
    get saturation() { return this._saturation; }
    set saturation(val) { this._saturation = val; this.material?.setProperty('saturation', val); }

    @property
    _brightness: number = 0;
    @property({ displayName: '明暗度', range: [-1, 1, 0.01], slide: true })
    get brightness() { return this._brightness; }
    set brightness(val) { this._brightness = val; this.material?.setProperty('brightness', val); }
    @property
    _strength: number = 1;
    @property({ displayName: '强度', range: [0, 1, 0.01], slide: true })
    get strength() { return this._strength; }
    set strength(val) { this._strength = val; this.material?.setProperty('strength', val); }
    material: Material = null;
    protected onEnable(): void {
        if (!this.checkMaterial()) return;
        this.material.setProperty('enable', 1);
        this.material.setProperty('strength', this._strength);
        this.material.setProperty('hue', this._hue);
        this.material.setProperty('saturation', this._saturation);
        this.material.setProperty('brightness', this._brightness);
        this.updateStyle();
        this.updateContentSize();
        this.node.on(NodeEventType.SIZE_CHANGED, this.updateContentSize, this);
    }
    protected onDisable(): void {
        if (this.material['_passes'].length !== 0) {
            this.material.setProperty('enable', 0);
        }
        this.node.off(NodeEventType.SIZE_CHANGED, this.updateContentSize, this);
    }
    //检测渲染组件的材质，是否与本脚本匹配
    checkMaterial(): boolean {
        let ur = this.node.getComponent(UIRenderer);
        ur['updateMaterial']();
        this.material = ur.getMaterialInstance(0);
        let className = js.getClassName(this);
        this.materialName = ur.customMaterial.name;
        if (this.materialName !== className) {
            console.warn(`节点"${this.node.name}"的组件"${className}.ts"与材质"${this.materialName}.mtl"不匹配！请设置材质为"${className}.mtl"并重新编译！`);
            return false;
        }
        ur instanceof Sprite && ur.spriteFrame && (ur.spriteFrame.packable = false);
        return true;
    }
    updateStyle(): void {
        this.material.setProperty('style', this._style);
        switch (this._style) {
            case Style.故障:
                this.material.setProperty('glitchDynamic', this._glitchDynamic ? 1 : 0);
                this.material.setProperty('glitchAmplitude', this._glitchAmplitude);
                break;
            case Style.马赛克:
                this.material.setProperty('mosaicSize', this._mosaicSize);
                break;
            case Style.电影胶片:
                this.material.setProperty('filmDynamic', this._filmDynamic ? 1 : 0);
                this.material.setProperty('filmGrain', this._filmGrain);
                this.material.setProperty('filmScratch', this._filmScratch);
                break;
        }
    }
    updateContentSize(): void {
        let ut = this.node.getComponent(UITransform);
        this.material.setProperty('texSize', new Vec2(ut.width, ut.height));
    }
}
declare global {
    module gi {
        class FilterFusion extends Component {
            static Style: typeof Style;  //滤镜样式枚举
            style: Style;                //滤镜样式
            glitchDynamic: boolean;      //故障动态
            glitchAmplitude: number;     //故障幅度
            mosaicSize: Vec2;            //马赛克尺寸
            filmDynamic: boolean;        //胶片动态
            filmGrain: number;           //胶片颗粒
            filmScratch: number;         //胶片划痕
            hue: number;                 //色相
            saturation: number;          //饱和度
            brightness: number;          //明暗度
            strength: number;            //强度
        }
    }
}
((globalThis as any).gi ||= {}).FilterFusion ||= Object.assign(FilterFusion, { Style: Style });